package middleware

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"net/http"
	"net/url"
	"shopstar/global"
	"time"
)

// 自定义一个结构体，实现 gin.ResponseWriter interface
type responseWriter struct {
	gin.ResponseWriter
	b *bytes.Buffer
}

// 重写 Write([]byte) (int, error) 方法
func (w responseWriter) Write(b []byte) (int, error) {
	//向一个bytes.buffer中写一份数据来为获取body使用
	w.b.Write(b)
	//完成gin.Context.Writer.Write()原有功能
	return w.ResponseWriter.Write(b)
}

func RequestLog() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		// 请求开始
		start := time.Now()
		// 请求路径
		path := ctx.Request.URL.Path

		writer := responseWriter{
			ctx.Writer,
			bytes.NewBuffer([]byte{}),
		}
		ctx.Writer = writer

		// 执行请求
		ctx.Next()
		// 请求处理的结束时间
		end := time.Now()
		// 请求执行时间
		cost := time.Since(start)
		// 获取状态
		status := ctx.Writer.Status()

		// 判断是GET还是POST
		var res url.Values
		if ctx.Request.Method == "GET" {
			res = ctx.Request.URL.Query()
		} else if ctx.Request.Method == "POST" {
			ctx.Request.ParseMultipartForm(32 << 20)
			res = ctx.Request.PostForm
		} else {
			res = nil
		}
		var resParams string
		if res != nil {
			jsonData, _ := json.Marshal(res)
			resParams = string(jsonData)
		}

		fields := []zap.Field{
			zap.Duration("start", start.Sub(start)),
			zap.Duration("end", start.Sub(end)),
			zap.Duration("cost", cost),
			// 基本信息
			zap.String("method", ctx.Request.Method),
			zap.Int("status", status),
			zap.String("errors", ctx.Errors.ByType(gin.ErrorTypePrivate).String()),

			// 请求参数
			zap.String("res-params", resParams),
			// 返回值
			zap.String("rep-json", writer.b.String()),
		}

		if status == http.StatusOK {
			global.Logs.Info(path, fields...)
		} else {
			global.Logs.Error(path, fields...)
		}

		fmt.Println(writer.b.String())
	}
}
